/*
  ******************************************************************************
  * @file    RGB_demo.c
  * @author  FreqChip Firmware Team
  * @version V1.0.0
  * @date    2024
  * @brief   RGB interface module Demo.
  ******************************************************************************
  * @attention
  *
  * Copyright (c) 2024 FreqChip.
  * All rights reserved.
  ******************************************************************************
*/
#include "app_lvgl.h"
#include "driver_st7282_rgb_hw.h"

#if (BOARD_SEL == BOARD_EVB_FR3092E_RGB)

#ifdef DISPLAY_TYPE_ST7282_RGB_HW
extern DMA_HandleTypeDef dma_display_handle;
static GPIO_InitTypeDef GPIO_Handle;
DISPLAY_HandTypeDef hdisplay;
struct_RGB_TypeDef_t rgb_handle;
unsigned char *coply = NULL;


#define RGB_VBPD    12// Vertical back porch
#define RGB_VFPD    8 // Vertical front porch
#define RGB_VSPW    4 // Vertical sync pulse width
//----------------------
#define RGB_HBPD    43 // Horizontal back porch
#define RGB_HFPD    8 // Horizontal front porch
#define RGB_HSPW    4 // Horizontal sync pulse width
//----------------------
#define RGB_ROW     480
#define RGB_COL     272   


void timer0_irq(void);


void virtual_spi_write(void * buffer,int len)
{
    int i,j;
    uint16_t nbit;

    uint16_t * data = (uint16_t *) buffer;

	for(i = 0; i< len; i++)
	{
		nbit = 0x0100;
		for(j = 0; j < 9; j ++)
		{			

			if(data[i] & nbit)
				__RGB_SPI_MOSI_SET();
			else
				__RGB_SPI_MOSI_CLEAR();
			//__nop();
	        //__nop();
	        __RGB_SPI_CLK_CLEAR();
            system_delay_us(2);
			__RGB_SPI_CLK_SET();
			nbit >>= 1;
            //__nop();
	        //__nop();
            system_delay_us(2);
		}
	}
}


static void rgb_reg_writer(uint16_t *fp_data, uint32_t size)
{
    __RGB_SPI_CS_SET(); 
    /* fp_Data[0] stores command, while others store data
       Bit8 set to 1 as data, otherwise it is a command
    */
    for(int i = 1; i < size; i++)
    {
      fp_data[i] = fp_data[i] + 0x100;
    }
    
    //__SPI_WRITE_DATA(fp_data,size); 
    virtual_spi_write(fp_data,size);
    
    __RGB_SPI_CS_RELEASE();
}


void rgb_init(void)
{
	
}

void rgb_display_start(struct_Timer_t *TIMERx, struct_RGB_TypeDef_t *hrgb, uint32_t fps, unsigned char *Imagedata)
{
    __TIMER_INIT(TIMERx, fps);
    __TIMER_INT_ENABLE(TIMERx);

    hrgb->rgb_TxData = Imagedata;
    hrgb->VerticalSignalCount = 0;
    hrgb->vs_back_count = 0;
    hrgb->vs_tvw_count = 0;

    //__TIMER_START(TIMERx);
    __DISPLAY_RGB_ENABLE(hdisplay.DISPLAYx);
    __DMA_TO_RGB_START_IT((uint32_t)(hrgb->rgb_TxData),(RGB_ROW * RGB_COL));
}


void rgb_timer_reinit(struct_Timer_t *TIMERx, uint32_t fps)
{
    NVIC_ClearPendingIRQ(TIMER0_IRQn);
    NVIC_EnableIRQ(TIMER0_IRQn);
    __TIMER_INIT(TIMERx, fps);
    __TIMER_INT_ENABLE(TIMERx);
}

const uint16_t rgb_color_table[] =
{
    0xf800,
    0x07e0,
    0x001f,
    0xffe0,
    0x07ff,
    0xf81f,
    0xf00f,
    0xffff,
    0x0000,
};

volatile uint8_t te_sign;
uint16_t test_couter = 0;
uint16_t test_id = 0;
volatile uint8_t fps_counter = 0;
volatile uint8_t refr_wait_sign = 0;
volatile uint8_t lock_timer_flag = 0;

__RAM_CODE void rgb_timer_IRQHandler(struct_Timer_t *TIMERx, struct_RGB_TypeDef_t *hrgb)
{
    __TIMER_CLEAR_IQR(TIMERx);

    // test_couter ++;
    // if(test_couter >= 66)
    // {
    //     test_couter = 0;
    //     uint16_t *test_buff = (uint16_t *)hrgb->rgb_TxData;
    //     test_id ++;
    //     test_id %= 9; 
    //     for(uint32_t i = 0; i< 272 * RGB_ROW; i++)
    //     {
    //         test_buff[i] = rgb_color_table[test_id];
    //     }
    //     fputc('.',NULL);
    // }

    // if (dma_get_tfr_Status(&dma_display_handle))
    // {
    //     dma_clear_tfr_Status(&dma_display_handle);
    // }
    // dma_start(&dma_display_handle,(uint32_t)(hrgb->rgb_TxData),(uint32_t)&hdisplay.DISPLAYx->TX_FIFO, (RGB_ROW * RGB_COL));
	//display_rgb_write_data(&hdisplay,(uint32_t)(hrgb->rgb_TxData),(RGB_ROW * RGB_COL));  	

    timer_stop(Timer0);
    te_sign = 0;
    //fputc('/', NULL);
    __DISPLAY_RGB_ENABLE(hdisplay.DISPLAYx);
    __DMA_TO_RGB_START_IT((uint32_t)(hrgb->rgb_TxData),(RGB_ROW * RGB_COL));

}


 /************************************************************************************
 * @fn      rgb_display_controller_init
 *
 * @brief   rgb_display_controller_init
 *

 */ 
static void rgb_display_controller_init(void)
{
    /* init display CLOCK */  
    __SYSTEM_DISPLAY_CLK_ENABLE();
    //__SYSTEM_DISPLAY_CLK_SELECT_COREH();
    __SYSTEM_DISPLAY_CLK_SELECT_SPLL();
    __SYSTEM_GPIOB_CLK_ENABLE();
    __SYSTEM_GPIOD_CLK_ENABLE();
    __SYSTEM_DMA0_CLK_ENABLE();
    __SYSTEM_TIMER0_CLK_ENABLE();

    printf("display clock:%d\r\n", system_get_peripheral_clock(PER_CLK_DISPLAY));

    //system_delay_us(2000);

    /* RGB io init */ 
    GPIO_Handle.Alternate = GPIO_FUNCTION_8;
    GPIO_Handle.Mode      = GPIO_MODE_AF_PP;
    GPIO_Handle.Pin       = 0xF000;
    GPIO_Handle.Pull      = GPIO_PULLUP;
    gpio_init(GPIOA, &GPIO_Handle);

    GPIO_Handle.Alternate = GPIO_FUNCTION_8;
    GPIO_Handle.Mode      = GPIO_MODE_AF_PP;
    #if BOARD_VERSION == BOARD_V1_0
    GPIO_Handle.Pin       = 0xFCF;
    #elif BOARD_VERSION == BOARD_V1_3
    GPIO_Handle.Pin       = 0xFCB;
    #else
    #error "choose correct board"
    #endif
    GPIO_Handle.Pull      = GPIO_PULLUP;
    gpio_init(GPIOB, &GPIO_Handle);

    GPIO_Handle.Alternate = GPIO_FUNCTION_8;
    GPIO_Handle.Mode      = GPIO_MODE_AF_PP;
    #if BOARD_VERSION == BOARD_V1_0
    // GPIO_Handle.Pin       = 0x3E00;             //DISABLE DE
    GPIO_Handle.Pin       = 0x3F00;             //ENABLE DE
    #elif BOARD_VERSION == BOARD_V1_3
    // GPIO_Handle.Pin       = 0x3E40;             //DISABLE DE
    GPIO_Handle.Pin       = 0x3F40;             //ENABLE DE
    #else
    #error "choose correct board"
    #endif
    GPIO_Handle.Pull      = GPIO_PULLUP;
    gpio_init(GPIOD, &GPIO_Handle);

    GPIO_Handle.Alternate = GPIO_FUNCTION_0;
    GPIO_Handle.Mode      = GPIO_MODE_OUTPUT_PP;
    GPIO_Handle.Pin       = RGB565_LCD_DISP_GPIO;
    GPIO_Handle.Pull      = GPIO_PULLUP;
    gpio_init(RGB565_LCD_DISP_PORT, &GPIO_Handle);     
    rgb_lcd_disp_set();

   /* backlight */ 
    #if BOARD_VERSION == BOARD_V1_0
    GPIO_Handle.Alternate = GPIO_FUNCTION_0;
    GPIO_Handle.Mode      = GPIO_MODE_OUTPUT_PP;
    GPIO_Handle.Pin       = RGB565_LCD_BACKLIGHT_GPIO;
    GPIO_Handle.Pull      = GPIO_PULLUP;
    gpio_init(RGB565_LCD_BACKLIGHT_PORT, &GPIO_Handle); 
	rgb_lcd_backlight_set();
    #elif BOARD_VERSION == BOARD_V1_3
    pmu_set_pin_dir(RGB565_LCD_BACKLIGHT_GPIO, PMU_GPIO_MODE_OUTPUT);
    rgb_lcd_backlight_set();
    #else
    #error "choose correct board"
    #endif

    //system_delay_us(1000 * 20);
    /* RGB Interaction Init */ 
    hdisplay.DISPLAYx = DISPLAY;
    hdisplay.RGB_Init.RGB_OUT_FORMAT_SELECT = RGB565_OUT;
    hdisplay.RGB_Init.RGB_IN_FORMAT_SELECT = RGB565_IN;
    hdisplay.Interface_Select = DISPLAY_INTERFACE_RGB;
    /* 
        RGB Timing Init
        1 Frame = HRES * VRES = 480x120
    */         
    hdisplay.RGB_Init.HBP = RGB_HBPD;
    hdisplay.RGB_Init.HFP = RGB_HFPD; 
    hdisplay.RGB_Init.VBP = RGB_VBPD;
    hdisplay.RGB_Init.VFP = RGB_VFPD;  
    hdisplay.RGB_Init.HSPW = RGB_HSPW; 
    hdisplay.RGB_Init.VSPW = RGB_VSPW;   
    hdisplay.RGB_Init.HRES = RGB_ROW;  
    hdisplay.RGB_Init.VRES = RGB_COL;
    display_init(&hdisplay);
    
    /* RGB_CLK =  (PER_CLK_RGB / 5*2) */              
    __DISPLAY_RGB_SET_PIXEL_CLK_DIV(hdisplay.DISPLAYx,8);    

    /* DMA Init */
    system_dmac_request_id_config(DISPLAY_TRANS,DMA0_REQUEST_ID_2); 
    dma_display_handle.DMAx                       = DMA0;
    dma_display_handle.Channel                    = DMA_Channel1;
    dma_display_handle.Init.Data_Flow             = DMA_M2P_DMAC;
    dma_display_handle.Init.Request_ID            = 2;
    dma_display_handle.Init.Source_Master_Sel     = DMA_AHB_MASTER_2;
    dma_display_handle.Init.Desination_Master_Sel = DMA_AHB_MASTER_3;
    dma_display_handle.Init.Source_Inc            = DMA_ADDR_INC_INC;
    dma_display_handle.Init.Desination_Inc        = DMA_ADDR_INC_NO_CHANGE;
    dma_display_handle.Init.Source_Width          = DMA_TRANSFER_WIDTH_16;
    dma_display_handle.Init.Desination_Width      = DMA_TRANSFER_WIDTH_16;
    dma_display_handle.Init.Source_Burst_Len      = DMA_BURST_LEN_32;
    dma_display_handle.Init.Desination_Burst_Len  = DMA_BURST_LEN_32;
    dma_init(&dma_display_handle);

    NVIC_ClearPendingIRQ(DMA0_IRQn);
    NVIC_EnableIRQ(DMA0_IRQn);
}


 /************************************************************************************
 * @fn      rgb_display_init
 *
 * @brief   rgb_display_init
 *

 */
__RAM_CODE void rgb_controller_reinit(void)
{
    /* init display CLOCK */  
    __SYSTEM_DISPLAY_CLK_ENABLE();
    //__SYSTEM_DISPLAY_CLK_SELECT_COREH();
    __SYSTEM_DISPLAY_CLK_SELECT_SPLL();
    __SYSTEM_GPIOB_CLK_ENABLE();
    __SYSTEM_GPIOD_CLK_ENABLE();
    __SYSTEM_DMA0_CLK_ENABLE();
    __SYSTEM_TIMER0_CLK_ENABLE();

    display_init(&hdisplay);
    /* RGB_CLK =  (PER_CLK_RGB / 5*2) */              
    __DISPLAY_RGB_SET_PIXEL_CLK_DIV(hdisplay.DISPLAYx,8);   

    system_dmac_request_id_config(DISPLAY_TRANS,DMA0_REQUEST_ID_2); 
    dma_init(&dma_display_handle);

    NVIC_ClearPendingIRQ(DMA0_IRQn);
    NVIC_EnableIRQ(DMA0_IRQn);

    NVIC_ClearPendingIRQ(TIMER0_IRQn);
    NVIC_EnableIRQ(TIMER0_IRQn);
}


 /************************************************************************************
 * @fn      rgb_display_init
 *
 * @brief   rgb_display_init
 *

 */
void rgb_display_init(void* buffer)
{
    coply = buffer;
    //coply = test_buff;

    /* rgb init */
    rgb_init();

    NVIC_ClearPendingIRQ(TIMER0_IRQn);
    NVIC_EnableIRQ(TIMER0_IRQn);
    // NVIC_ClearPendingIRQ(DMA0_IRQn);
    // NVIC_EnableIRQ(DMA0_IRQn);

    rgb_display_start(Timer0, &rgb_handle, 1, coply);

    printf("%s:%d\r\n", __func__, __LINE__);
}

void stop_refresh_timer(void)
{
    timer_int_disable(Timer0);
    timer_stop(Timer0);
}

void start_refresh_timer(void)
{
    __TIMER_INT_ENABLE(Timer0);
    __TIMER_START(Timer0);
   
}


void st7282_init(void* buffer)
{
	rgb_display_controller_init();
	rgb_display_init(buffer);
}

__RAM_CODE void timer0_irq(void)
{
    rgb_timer_IRQHandler(Timer0, &rgb_handle);
}

__RAM_CODE void st7282_rgb_display_dma_irq(void)
{
    if (dma_get_tfr_Status(&dma_display_handle))
    {
        dma_clear_tfr_Status(&dma_display_handle);
        if(refr_wait_sign)
        {
            //fputc('*', NULL);
            __DISPLAY_RGB_DISABLE(hdisplay.DISPLAYx);
            __TIMER_START(Timer0);
        }
        else
        {
            //fputc('.', NULL);
            __DISPLAY_RGB_ENABLE(hdisplay.DISPLAYx);
            __DMA_TO_RGB_START_IT((uint32_t)(rgb_handle.rgb_TxData),(RGB_ROW * RGB_COL));            
        }
        te_sign = 1;
        fps_counter ++;
    }
}

void st7282_power_on(void)
{

    rgb_timer_reinit(Timer0,1);
    dma_clear_tfr_Status(&dma_display_handle);
    NVIC_ClearPendingIRQ(DMA0_IRQn);
    NVIC_EnableIRQ(DMA0_IRQn);
    __DISPLAY_RGB_ENABLE(hdisplay.DISPLAYx);
    __DMA_TO_RGB_START_IT((uint32_t)(rgb_handle.rgb_TxData),(RGB_ROW * RGB_COL));
    rgb_lcd_disp_set();
    // rgb_lcd_backlight_set();

}

void st7282_power_off(void)
{
    rgb_lcd_backlight_release();
    rgb_lcd_disp_release();
    __DISPLAY_RGB_DISABLE(hdisplay.DISPLAYx);
    NVIC_ClearPendingIRQ(DMA0_IRQn);
    NVIC_DisableIRQ(DMA0_IRQn);
}

#endif

#endif
